package ca.etsmtl.logti.log619.lab05.analyser;

import java.util.ArrayList;
import java.util.HashMap;

import ca.etsmtl.logti.log619.lab05.SpamType;
import ca.etsmtl.logti.log619.lab05.filter.EmailFilter;

/**
 * This class is responsible of collecting and returning information about the emails that were analyzed.
 * @author Maxime Caumartin<maxime.caumartin.1@ens.etsmtl.ca>
 */
public class Analyser implements SpamAnalyser {
	
	/**
	 * Contains the list of all Messages and their results
	 */
	private HashMap<String,MessageResult> lst = new HashMap<String,MessageResult>();
	
	/**
	 * Private class that defines the structure that saves the email results. 
	 * @author Maxime Caumartin<maxime.caumartin.1@ens.etsmtl.ca>
	 */
	private class MessageResult {
		public HashMap<String, Byte> results = new HashMap<String, Byte>();
		public SpamType type;
		
		public MessageResult(SpamType type)
		{
			this.type = type;
		}
	}

	@Override
	public void addResult(String messagePath, String filterName, SpamType origInfo ,
			byte b) {
		if (!lst.containsKey(messagePath))
			lst.put(messagePath, new MessageResult(origInfo));
		
		lst.get(messagePath).results.put(filterName, b);
		needToAnalyse = true;
	}
	
	private int spamCount = 0;
	private int spamNoInfo = 0;
	private int falsePositive = NO_INFO;
	private int falseNegative = NO_INFO;
	
	private ArrayList<String> spamInfo = new ArrayList<String>(); 
	
	private boolean needToAnalyse = true;

	@Override
	public String analyserResult()
	{
		
		StringBuilder build = new StringBuilder();
		for (String s : spamInfo)
			build.append(s);
		return build.toString();
	}
	
	private void analyse()
	{
		// Reset variables
		this.spamCount = 0;
		this.falsePositive = NO_INFO;
		this.falseNegative = NO_INFO;
		this.spamNoInfo = 0;
		
		for(String key : lst.keySet())
		{
			MessageResult tmr = lst.get(key);
			StringBuffer sB = new StringBuffer();
			
			// Determine if this file is spam or not.
			int percentageMean = 0;
			int donTCountFilters = 0;
			
			for (String filter : tmr.results.keySet())
			{
				int value = (int) tmr.results.get(filter);
				if (value != EmailFilter.CANT_SAY)
				{
					percentageMean += (int) (tmr.results.get(filter) /** FilterFactory.getFilter(filter).getConfidenceLevel()*/);
					sB.append(String.format(" %1$s (%2$s)", filter,value));
				}
				else
					donTCountFilters++;
			}
			
			int spamRate = percentageMean / (tmr.results.keySet().size() - donTCountFilters);
			
			if (spamRate >= SPAM_THREASHOLD)
			{
				spamCount++;
				//this.spamInfo.add(key + " is SPAM : \n\t" + sB.toString());
			}
				//this.spamInfo.add(key + " is HAM : \n\t" + sB.toString());
			
			if (tmr.type == SpamType.mmmm)
				spamNoInfo++;
			else
				if (tmr.type == SpamType.ham && spamRate >= SPAM_THREASHOLD)
				{
					falsePositive++;
					this.spamInfo.add(key +  " - false positive : " + sB.toString() + "\n");
				}
				else if (tmr.type == SpamType.spam && spamRate < SPAM_THREASHOLD)
				{
					falseNegative++;
					this.spamInfo.add(key + " - false negative : " + sB.toString() + "\n");
				}
		}
		needToAnalyse = false;
	}
	
	

	@Override
	public int getSPAMcount()
	{
		if (needToAnalyse)
			analyse();
		return this.spamCount;
	}

	@Override
	public int getHAMcount()
	{
		if (needToAnalyse)
			analyse();
		return (this.lst.size() - this.spamCount);
	}

	@Override
	public int getFalsePositives()
	{
		if (needToAnalyse)
			analyse();
		return this.falsePositive;
	}

	@Override
	public int getFalseNegatives()
	{
		if (needToAnalyse)
			analyse();
		return this.falseNegative;
	}

	@Override
	public int getTotalCount()
	{
		return this.lst.size();
	}
}
